"""
任务分配
"""
import random
import pandas as pd
import copy
import itertools

from .situation import *


class TaskAllocation(object):
    def __init__(self):
        self.operators = []  # 我方算子集合
        """
        类似operators的数据类型
        """
        self.task = None  # 任务集合
        """(list)
        [task1, task2, task3, task4,...]
        """
        self.mission = None  # 指挥意图 给mission的预留接口
        self.situation = None  # 获取资源集合
        self.time = None  # 任务分配允许时间

        self.efficiency = None  # 单个算子行为树效能值
        self.addition = None  # 两个算子行为树对于完成任务的加成值

        self.union = None
        self.max_member = 4

    def setup(self, agent):  # 初始化函数
        for operator in agent.scenario["operators"]:
            if operator['color'] == agent.color:
                self.operators.append(operator)
        self.task = [0, 1, 2]
        self.mission = 0
        self.situation = None
        self.time = 500
        self.efficiency = {0: {(0, 0): 0.58, (0, 1): 0.41, (0, 2): 0.24, (1, 0): 0.36, (1, 1): 0.25, (1, 2): 0.15,
                               (2, 0): 0.26, (2, 1): 0.18, (2, 2): 0, (3, 0): 0.22, (3, 1): 0.15, (3, 2): 0.08,
                               (4, 0): 0.33, (4, 1): 0.23, (4, 2): 0.15, (5, 0): 0, (5, 1): 0, (5, 2): 0,
                               (7, 0): 0.14, (7, 1): 0.11, (7, 2): 0.08}}
        """(dict)
        {mission: {(sub_type, task): efficiency, (sub_type, task): efficiency ...}}
        """

        self.addition = {0: {((0, 0), (0, 0)): 0.72, ((0, 0), (0, 1)): 0.61, ((0, 0), (0, 2)): 0.55,
                             ((0, 1), (0, 1)): 0.51, ((0, 1), (0, 2)): 0.40, ((0, 2), (0, 2)): 0.28,
                             ((0, 0), (1, 0)): 0.49, ((0, 0), (1, 1)): 0.42, ((0, 0), (1, 2)): 0.37,
                             ((0, 1), (1, 1)): 0.33, ((0, 1), (1, 2)): 0.27, ((0, 2), (1, 2)): 0.19,
                             ((0, 0), (2, 0)): 0.52, ((0, 0), (2, 1)): 0.45,
                             ((0, 1), (2, 1)): 0.25,
                             ((0, 0), (3, 0)): 0.44, ((0, 0), (3, 1)): 0.37, ((0, 0), (3, 2)): 0.34,
                             ((0, 1), (3, 1)): 0.29, ((0, 1), (3, 2)): 0.34, ((0, 2), (3, 2)): 0.17,
                             ((0, 0), (4, 0)): 0.45, ((0, 0), (4, 1)): 0.38, ((0, 0), (4, 2)): 0.34,
                             ((0, 1), (4, 1)): 0.30, ((0, 1), (4, 2)): 0.25, ((0, 2), (4, 2)): 0.17,
                             ((0, 0), (7, 0)): 0.76, ((0, 0), (7, 1)): 0.65, ((0, 0), (7, 2)): 0.58,
                             ((0, 1), (7, 1)): 0.51, ((0, 1), (7, 2)): 0.42, ((0, 2), (7, 2)): 0.31,
                             ((1, 0), (0, 0)): 0.52, ((1, 0), (0, 1)): 0.44, ((1, 0), (0, 2)): 0.40,
                             ((1, 1), (0, 1)): 0.35, ((1, 1), (0, 2)): 0.38, ((1, 2), (0, 2)): 0.21,
                             ((1, 0), (1, 0)): 0.71, ((1, 0), (1, 1)): 0.60, ((1, 0), (1, 2)): 0.55,
                             ((1, 1), (1, 1)): 0.58, ((1, 1), (1, 2)): 0.39, ((1, 2), (1, 2)): 0.28,
                             ((1, 0), (2, 0)): 0.75, ((1, 0), (2, 1)): 0.64,
                             ((1, 1), (2, 1)): 0.50,
                             ((1, 0), (3, 0)): 0.86, ((1, 0), (3, 1)): 0.73, ((1, 0), (3, 2)): 0.66,
                             ((1, 1), (3, 1)): 0.58, ((1, 1), (3, 2)): 0.47, ((1, 2), (3, 2)): 0.34,
                             ((1, 0), (4, 0)): 0.47, ((1, 0), (4, 1)): 0.40, ((1, 0), (4, 2)): 0.36,
                             ((1, 1), (4, 1)): 0.31, ((1, 1), (4, 2)): 0.26, ((1, 2), (4, 2)): 0.34,
                             ((1, 0), (5, 0)): 0.39, ((1, 0), (5, 1)): 0.33, ((1, 0), (5, 2)): 0.30,
                             ((1, 1), (5, 1)): 0.26, ((1, 1), (5, 2)): 0.21, ((1, 2), (5, 2)): 0.16,
                             ((1, 0), (7, 0)): 0.92, ((1, 0), (7, 1)): 0.92, ((1, 0), (7, 2)): 0.83,
                             ((1, 1), (5, 1)): 0.72, ((1, 1), (7, 2)): 0.59, ((1, 2), (7, 2)): 0.43,
                             ((2, 0), (0, 0)): 0.25, ((2, 0), (0, 1)): 0.21, ((2, 0), (0, 2)): 0.19,
                             ((2, 1), (0, 1)): 0.16, ((2, 1), (0, 2)): 0.14,
                             ((2, 0), (1, 0)): 0.75, ((2, 0), (1, 1)): 0.64, ((2, 0), (1, 2)): 0.58,
                             ((2, 1), (1, 1)): 0.50, ((2, 1), (1, 2)): 0.41,
                             ((2, 0), (2, 0)): 0.96, ((2, 0), (2, 1)): 0.80,
                             ((2, 1), (2, 1)): 0.53,
                             ((2, 0), (3, 0)): 0.80, ((2, 0), (3, 1)): 0.68, ((2, 0), (3, 2)): 0.54,
                             ((2, 1), (3, 1)): 0.44, ((2, 1), (3, 2)): 0.32,
                             ((2, 0), (4, 0)): 0.57, ((2, 0), (4, 1)): 0.48, ((2, 0), (4, 2)): 0.44,
                             ((2, 1), (4, 1)): 0.38, ((2, 1), (4, 2)): 0.41,
                             ((2, 0), (5, 0)): 0.49, ((2, 0), (5, 1)): 0.42, ((2, 0), (5, 2)): 0.38,
                             ((2, 1), (5, 1)): 0.33, ((2, 1), (5, 2)): 0.27,
                             ((2, 0), (7, 0)): 0.82, ((2, 0), (7, 1)): 0.69, ((2, 0), (7, 2)): 0.63,
                             ((2, 1), (7, 1)): 0.55, ((2, 1), (7, 2)): 0.45,
                             ((3, 0), (0, 0)): 0.23, ((3, 0), (0, 1)): 0.20, ((3, 0), (0, 2)): 0.17,
                             ((3, 1), (0, 1)): 0.15, ((3, 1), (0, 2)): 0.13, ((3, 2), (0, 2)): 0.09,
                             ((3, 0), (1, 0)): 0.32, ((3, 0), (1, 1)): 0.27, ((3, 0), (1, 2)): 0.24,
                             ((3, 1), (1, 1)): 0.21, ((3, 1), (1, 2)): 0.18, ((3, 2), (1, 2)): 0.13,
                             ((3, 0), (2, 0)): 0.58, ((3, 0), (2, 1)): 0.49,
                             ((3, 1), (2, 1)): 0.39,
                             ((3, 0), (3, 0)): 0.29, ((3, 0), (3, 1)): 0.25, ((3, 0), (3, 2)): 0.22,
                             ((3, 1), (3, 1)): 0.19, ((3, 1), (3, 2)): 0.16, ((3, 2), (3, 2)): 0.12,
                             ((3, 0), (4, 0)): 0.39, ((3, 0), (4, 1)): 0.33, ((3, 0), (4, 2)): 0.30,
                             ((3, 1), (4, 1)): 0.26, ((3, 1), (4, 2)): 0.21, ((3, 2), (4, 2)): 0.15,
                             ((3, 0), (7, 0)): 0.94, ((3, 0), (7, 1)): 0.79, ((3, 0), (7, 2)): 0.63,
                             ((3, 1), (7, 1)): 0.52, ((3, 1), (7, 2)): 0.37, ((3, 2), (7, 2)): 0.56,
                             ((4, 0), (0, 0)): 0.56, ((4, 0), (0, 1)): 0.48, ((4, 0), (0, 2)): 0.43,
                             ((4, 1), (0, 1)): 0.38, ((4, 1), (0, 2)): 0.31, ((4, 2), (0, 2)): 0.22,
                             ((4, 0), (1, 0)): 0.45, ((4, 0), (1, 1)): 0.38, ((4, 0), (1, 2)): 0.35,
                             ((4, 1), (1, 1)): 0.30, ((4, 1), (1, 2)): 0.25, ((4, 2), (1, 2)): 0.18,
                             ((4, 0), (2, 0)): 0.48, ((4, 0), (2, 1)): 0.41,
                             ((4, 1), (2, 1)): 0.32,
                             ((4, 0), (3, 0)): 0.41, ((4, 0), (3, 1)): 0.35, ((4, 0), (3, 2)): 0.31,
                             ((4, 1), (3, 1)): 0.27, ((4, 1), (3, 2)): 0.23, ((4, 2), (3, 2)): 0.16,
                             ((4, 0), (4, 0)): 0.51, ((4, 0), (4, 1)): 0.43, ((4, 0), (4, 2)): 0.39,
                             ((4, 1), (4, 1)): 0.34, ((4, 1), (4, 2)): 0.28, ((4, 2), (4, 2)): 0.20,
                             ((4, 0), (5, 0)): 0.35, ((4, 0), (5, 1)): 0.30, ((4, 0), (5, 2)): 0.27,
                             ((4, 1), (5, 1)): 0.23, ((4, 1), (5, 2)): 0.19, ((4, 2), (5, 2)): 0.14,
                             ((4, 0), (7, 0)): 0.77, ((4, 0), (7, 1)): 0.65, ((4, 0), (7, 2)): 0.59,
                             ((4, 1), (7, 1)): 0.51, ((4, 1), (7, 2)): 0.42, ((4, 2), (7, 2)): 0.31,
                             ((5, 0), (1, 0)): 0.39, ((5, 0), (1, 1)): 0.33, ((5, 0), (1, 2)): 0.30,
                             ((5, 1), (1, 1)): 0.26, ((5, 1), (1, 2)): 0.21, ((5, 2), (1, 2)): 0.16,
                             ((5, 0), (2, 0)): 0.49, ((5, 0), (2, 1)): 0.42,
                             ((5, 1), (2, 1)): 0.33,
                             ((5, 0), (4, 0)): 0.35, ((5, 0), (4, 1)): 0.33, ((5, 0), (4, 2)): 0.27,
                             ((5, 1), (4, 1)): 0.23, ((5, 1), (4, 2)): 0.19, ((5, 2), (4, 2)): 0.14
                             }}
        """(dict)
        {mission:((sub_type, task), (sub_type, task)): addition, ((sub_type, task), (sub_type, task)): addition...}
        """


    def step(self, agent, mission=None, param=None):
        """
        任务分配函数
        return： task_allocation  任务分配结果
                (dict)
                {obj_id: [task，参数], obj_id: [task，参数]...}
        """
        task_allocation = {}
        result_1 = []
        result_2 = []
        result_3 = []
        self.situation = agent.situation
        time = self.time
        union = self.union_born(self)  # 生成初始联盟
        # while 1:
        while time:
            # task_result = self.alter_task_allocation()
            # union = {0: [(17, 1)], 1: [(16, 2), (18, 2), (19, 1)], 2: [(20, 2), (21, 1), (22, 2), (23, 1)]}
            # union = self.union_born(self)  # 生成初始联盟
            result_1.clear()
            result_2.clear()
            result_3.clear()
            union_set = self.change_union(union, self.max_member)  # 遍历算子转移联盟后所有的联盟集合
            for single in union_set:
                result_single = self.add_calculate(agent, single)
                result_1.append(result_single)
            if time == 1:
                print(1)
            b = result_1.index(max(result_1))
            union_result_1 = union_set[b]  # 找到效能最大的联盟
            union_set_2 = self.change_betree(union_result_1)  # 为算子改变行为树
            for single_2 in union_set_2:
                result_single = self.add_calculate(agent, single_2)
                result_2.append(result_single)
            c = result_2.index(max(result_2))
            union_result_2 = union_set_2[c]  # 找到效能最大的联盟
            union_set_3 = self.change_union(union_result_2, self.max_member)
            for single_3 in union_set_3: # 遍历算子转移联盟后所有的联盟集合
                result_single = self.add_calculate(agent, single_3)
                result_3.append(result_single)
            d = result_3.index(max(result_3))
            union = union_set_3[d]  # 找到效能最大的联盟
            # for u4 in union_set_4:
            #     union_set_5 = self.change_union(u4, self.max_member)
            #     print(union_set_5)

            # a = self.add_calculate(agent, union)
            # print(a)
            time -= 1

        print(union)
        return union

    def allocation(self, agent):
        """
        计算期望回报函数
        param： task 一种任务分配的情况
        return： int 此种分配下的回报值
        """
        type_group = []  # 存储所有算子的sub_type
        alliance_value = {}  # 存储组合的关联指标
        group_result = []  # 最后确定好的算子类型和行为树组合
        efficiency_standby = {}  # 存储需要用到的单个算子行为树的效能值
        task_result = {}  # 分配好的任务方案
        if self.mission in self.efficiency and self.mission in self.addition:  # 存储当前mission对应下的效能值和加成值
            efficiency = self.efficiency[self.mission]
            addition = self.addition[self.mission]
        else:
            return 0
        # enemy_situation = self.forecast_enemy_situation()
        # result = self.success_rate(task, enemy_situation) + self.operators_loss_rate(task, enemy_situation) + \
        #         self.destroy_enemy_score(task, enemy_situation)
        for operator in self.operators:  # 取出所有算子的sub_type
            type_group.append(operator['sub_type'])
        operator_tree = list(itertools.product(type_group, self.task))  # 算子和行为树两两组合
        group = list(itertools.combinations(operator_tree, 2))  # 对所有算子类型和行为树进行两两组合
        for group_single in group:  # 筛选出有加成的所有组合及关联指标
            if group_single == ((5, 0), (5, 0)):
                print(1)
            for i in addition:
                if (i == group_single) or (i == (group_single[1], group_single[0])):
                    if (group_single[0] in efficiency) and (group_single[1] in efficiency):
                        alliance_value[group_single] = (addition[i] * (efficiency[group_single[0]] +
                                                                       efficiency[group_single[1]]))
                        break
                    else:
                        continue
                else:
                    continue

        def set_rank(a_dict):  # 字典根据value从高到低排序
            a_sort_list = sorted(a_dict.items(), key=lambda x: x[1], reverse=True)
            a_sort_dict = {}
            for n, s in a_sort_list:
                a_sort_dict[n] = s
            return a_sort_dict

        alliance_sort = set_rank(alliance_value)  # 对组合的关联指标从高到低排序
        standby = copy.deepcopy(type_group)
        for alliance_single, value in alliance_sort.items():  # 根据关联指标先确定第一个组合，后面就都可以确定了
            alliance_0 = alliance_single[0]
            alliance_1 = alliance_single[1]
            while 1:
                if alliance_0[0] in standby:
                    standby.remove(alliance_0[0])
                    if alliance_1[0] in standby:
                        group_result.append(alliance_0)
                        group_result.append(alliance_1)
                        # alliance_result.update({group_result.index(alliance_single): value})
                        standby.remove(alliance_1[0])
                    else:
                        standby.append(alliance_0[0])
                        break
                else:
                    break
        if standby:  # 根据单个的效能值给没有组合的算子分配行为树
            for standby_one in standby:
                for efficiency_one, value in efficiency.items():
                    if standby_one == efficiency_one[0]:
                        efficiency_standby.update({efficiency_one: value})
                group_result.append(max(efficiency_standby, key=efficiency_standby.get))
        operators = copy.deepcopy(self.operators)
        for group_pair in group_result:  # 把最终方案从元祖形式改为字典形式
            task_dict = {}
            group_pair_list = list(group_pair)
            for operator in operators:
                if operator['sub_type'] == group_pair_list[0]:
                    task_dict[operator['obj_id']] = group_pair_list[1]
                    operators.remove(operator)
                    task_result.update(task_dict)
                    break
                else:
                    continue
        return task_result

    def success_rate(self, task, enemy_situation):
        """
        计算完成任务的成功率
        param： task 一种任务分配的情况
                enemy_situation  此时或我方完成任务期间敌方的可能兵力情况
        return： int 此种分配下完成任务的成功率
        """
        return 0.7

    def operators_loss_rate(self, task, enemy_situation):
        """
        计算我方兵力的损失概率
        param： task 一种任务分配的情况
                enemy_situation  此时或我方完成任务期间敌方的可能兵力情况
        return： int 我方兵力的损失概率
        """
        return 0.4

    def destroy_enemy_score(self, task, enemy_situation):  # 计算当前分配下完成任务过程中能打掉敌方的分数
        """
        计算完成任务过程中能打掉敌方的分数
        param： task 一种任务分配的情况
                enemy_situation  此时或我方完成任务期间敌方的可能兵力情况
        return： int 完成任务过程中能打掉敌方的分数
        """
        return 1

    def forecast_enemy_situation(self):  # 此时或我方完成任务期间敌方的可能兵力情况
        """
        预估我方完成任务期间敌方的可能兵力情况
        param： task 一种任务分配的情况
                enemy_situation  此时或我方完成任务期间敌方的可能兵力情况
        return： enemy_situation （dict） 敌方可能的兵力情况
        """
        enemy_situation = {}
        return enemy_situation

    def correct(self):
        """
        修正函数
        根据实战结果对任务的期望回报值进行修正
        return： int 修正值
        """
        return 0.1

    def alter_task_allocation(self):
        """
        改变算子分配任务函数
        return： task  根据候选任务生成一种任务分配的情况
                (dict)
                {obj_id: task(int), obj_id: task(int)...}
        """
        task = {}
        for operator in self.operators:
            task.update({operator['obj_id']: random.choice(self.task)})
        return task

    def infer_pos(self, agent, task, param):
        """
        推理行为树参数
        """
        tree_pos = {}
        enemy_IFV_pos = []
        enemies = []
        enemies_not_infantry = []
        # for operator in self.operators:
        #     tree_pos.update({operator['obj_id']: 4359})
        enemies_situation = self.situation.enemies  # 敌方算子情况
        cities = [pos['coord'] for pos in agent.observation['cities']]
        for enemy_operator in agent.observation['operators'] + agent.observation['passengers']:
            if enemy_operator['color'] != agent.color:
                enemies.append(enemy_operator['cur_hex'])  # 当前能观察到的所有敌方算子位置
                if enemy_operator['sub_type'] != BopSubType.Infantry:
                    enemies_not_infantry.append(enemy_operator['cur_hex'])  # 当前能观察到的除步兵外所有敌方算子位置
        for enemy_id, observation in enemies_situation.items():
            if observation['color'] != agent.color and observation['sub_type'] == BopSubType.IFV:
                for pos, step in observation['historical_positions'].items():
                    if (agent.observation['time']['cur_step'] - step[1] < 1) and (step[1] - step[0] > 75):
                        enemy_IFV_pos.append(pos)  # 所有敌方可能静止的战车位置
        for obj_id, tree in task.items():
            bop = agent.get_bop(obj_id)
            if bop:
                if bop['sub_type'] in [BopSubType.CruiseMissle, BopSubType.Drone]:  # 巡飞弹、无人机不需要传参
                    tree_pos.update({obj_id: None})
                elif bop['sub_type'] == BopSubType.UGV:  # 战车：只有一颗行为树
                    if param:  # 有参数就传参数
                        tree_pos.update({obj_id: param})
                    else:
                        if enemy_IFV_pos:  # 没有参数随机选一个敌方战车的位置
                            pos = random.choice(enemy_IFV_pos)
                            tree_pos.update({obj_id: pos})
                            enemy_IFV_pos.remove(pos)
                        else:  # 没有战车就传夺控点
                            tree_pos.update({obj_id: random.choice(cities)})
                elif bop['sub_type'] == BopSubType.Tank:  # 坦克
                    if tree == 0:  # 进攻行为树
                        if param:  # 有参数就传参数
                            tree_pos.update({obj_id: param})
                        else:  # 没有参数就在敌方位置非步兵和夺控点中间选
                            standby_pos = enemies_not_infantry + cities
                            if bop['cur_hex'] in standby_pos:
                                standby_pos.remove(bop['cur_hex'])
                            pos = random.choice(standby_pos)
                            tree_pos.update({obj_id: pos})
                            if pos in enemies:
                                enemies.remove(pos)
                            if pos in enemies_not_infantry:
                                enemies_not_infantry.remove(pos)
                    elif tree == 1:  # 防御行为树
                        if param:  # 有参数就传参数
                            tree_pos.update({obj_id: param})
                        else:  # 没有 如果据夺控点过远传距离最近的敌方算子位置
                            distances = [agent.map.get_distance(city, bop['cur_hex']) for city in cities]
                            city = cities[distances.index(max(distances))]
                            if agent.map.get_distance(city, bop['cur_hex']) >= 18:
                                distances = [agent.map.get_distance(pos, bop['cur_hex']) for pos in enemies]
                                index = distances.index(min(distances))
                                standby_pos = enemies[index]
                                if standby_pos:
                                    tree_pos.update({obj_id: standby_pos})
                                    enemies_not_infantry.remove(standby_pos)
                                    if standby_pos in enemies_not_infantry:
                                        enemies_not_infantry.remove(standby_pos)
                                else:  # 没有敌方算子传夺控点
                                    tree_pos.update({obj_id: random.choice(cities)})
                            else:
                                tree_pos.update({obj_id: random.choice(cities)})
                    else:  # 侦查行为树
                        if param:  # 有参数就传参数
                            tree_pos.update({obj_id: param})
                        else:  # 没有参数随机传敌方位置
                            standby_pos = enemies + cities
                            if bop['cur_hex'] in standby_pos:
                                standby_pos.remove(bop['cur_hex'])
                            pos = random.choice(standby_pos)
                            tree_pos.update({obj_id: pos})
                            if pos in enemies:
                                enemies.remove(pos)
                            if pos in enemies_not_infantry:
                                enemies_not_infantry.remove(pos)
                elif bop['sub_type'] == BopSubType.IFV:  # 战车
                    if tree == 0:  # 进攻行为树
                        if param:  # 有参数就传参数
                            tree_pos.update({obj_id: param})
                        else:  # 没有参数传敌方位置和夺控位置
                            standby_pos = enemies + cities
                            if bop['cur_hex'] in standby_pos:
                                standby_pos.remove(bop['cur_hex'])
                            pos = random.choice(standby_pos)
                            tree_pos.update({obj_id: pos})
                            if pos in enemies:
                                enemies.remove(pos)
                            if pos in enemies_not_infantry:
                                enemies_not_infantry.remove(pos)
                    elif tree == 1:  # 防御行为树
                        if param:  # 有参数就传参数
                            tree_pos.update({obj_id: param})
                        else:  # 没有参数传夺控点
                            tree_pos.update({obj_id: random.choice(cities)})
                    else:  # 侦查行为树
                        if param:   # 有参数就传参数
                            tree_pos.update({obj_id: param})
                        else:  # 没有参数就在敌方位置和夺控点中间选
                            standby_pos = enemies + cities
                            if bop['cur_hex'] in standby_pos:
                                standby_pos.remove(bop['cur_hex'])
                            pos = random.choice(standby_pos)
                            tree_pos.update({obj_id: pos})
                            if pos in enemies:
                                enemies.remove(pos)
                            if pos in enemies_not_infantry:
                                enemies_not_infantry.remove(pos)
                elif bop['sub_type'] == BopSubType.Infantry:  # 步兵：没有侦查行为树
                    if tree == 0:  # 进攻行为树
                        if param:  # 有参数就传参数
                            tree_pos.update({obj_id: param})
                        else:  # 没有参数随机选一个敌方战车的位置
                            if enemy_IFV_pos:
                                tree_pos.update({obj_id: random.choice(enemy_IFV_pos)})
                            else:
                                tree_pos.update({obj_id: random.choice(cities)})
                    elif tree == 1:  # 防御行为树
                        if param:  # 有参数就传参数
                            tree_pos.update({obj_id: param})
                        else:  # 没有参数就不传
                            tree_pos.update({obj_id: None})
        return tree_pos

    def task_alter_allocation(self,agent):
        """
        毕珊宁 改变算子分配任务函数
        return： task  根据候选任务生成一种任务分配的情况
                (dict)
                {obj_id: task(int), obj_id: task(int)...}
        """

        def weight_sampling(w_list):
            ran = np.random.uniform(0, 1)
            sum = 0
            for i in range(len(w_list)):
                sum += w_list[i]
                if (ran < sum):
                    return i

        # 提取权重
        if self.mission in self.efficiency and self.mission in self.addition:  # 存储当前mission对应下的效能值和加成值
            efficiency = self.efficiency[self.mission]
        else:
            return 0
        task_new = {}
        w_list = []
        num_list = []
        result = []
        for operator in self.operators:
            obj_id = operator['obj_id']
            bop = agent.get_bop(obj_id)
            if bop:
                for subtype, effi0 in efficiency.items():
                    if subtype == bop['sub_type']:
                        for type, effi_single in effi0.items():
                            w_list.append(effi_single)
                        for i in range(100):
                            num_list.append(weight_sampling(w_list))
                        account_list = [num_list.count(0), num_list.count(1),
                                        num_list.count(2)]  # 进行计数
                        for j in account_list:
                            result.append(j/sum(account_list))
                        result0 = tuple(result)
                        num_lst = [0, 1, 2]
                        betree = random.choices(num_lst, weights=result0, k=1)
                        task_new.update({operator['obj_id']:betree[0]})
                        result.clear()
                        w_list.clear()
        return task_new

    def calculate_return(self, agent, task):
        """
        计算期望回报函数（两个一组）
        param： task 一种任务分配的情况
        return： int 此种分配下的回报值
        """
        group_standby = []
        alliance = []
        alliance_value = {}
        alliance_result = []
        scheme_value = 0
        if self.mission in self.efficiency and self.mission in self.addition:  # 存储当前mission对应下的效能值和加成值
            efficiency = self.efficiency[self.mission]
            addition = self.addition[self.mission]
        else:
            return 0
        # enemy_situation = self.forecast_enemy_situation()
        # result = self.success_rate(task, enemy_situation) + self.operators_loss_rate(task, enemy_situation) + \
        #         self.destroy_enemy_score(task, enemy_situation)
        for obj_id, obj_task in task.items():
            bop = agent.get_bop(obj_id)
            if bop:
                group_standby.append((bop['sub_type'], obj_task))
            else:
                return 0
        group = list(itertools.combinations(group_standby, 2))
        for group_single in group:
            for i in addition:
                if (group_single[0] in i) and (group_single[1] in i):
                    alliance.append(group_single)
                else:
                    continue
        for alliance_single in alliance:
            for i in addition:
                if (alliance_single[0] in i) and (alliance_single[1] in i):
                    if addition.get(alliance_single):
                        alliance_value.update({alliance_single: addition[i]})
                        # {alliance_single: addition[i] * (efficiency[alliance_single[0][0]][alliance_single[0][1]] +
                        #                                  efficiency[alliance_single[1][0]][alliance_single[1][1]])})
                else:
                    continue

        def set_rank(a_dict):
            a_sort_list = sorted(a_dict.items(), key=lambda x: x[1], reverse=True)
            a_sort_dict = {}
            for n, s in a_sort_list:
                a_sort_dict[n] = s
            return a_sort_dict

        alliance_sort = set_rank(alliance_value)
        standby = copy.deepcopy(group_standby)
        for alliance_single in alliance_sort.keys():
            alliance_0 = alliance_single[0]
            alliance_1 = alliance_single[1]
            if alliance_0 in standby:
                standby.remove(alliance_0)
                if alliance_1 in standby:
                    alliance_result.append(alliance_single)
                    standby.remove(alliance_1)
                else:
                    standby.append(alliance_0)
            else:
                break
        for efficiency_single in standby:
            if efficiency_single in efficiency.keys():
                scheme_value += efficiency[efficiency_single]
        for alliance_single in alliance_result:
            for i in addition:
                if (alliance_single[0] in i) and (alliance_single[1] in i):
                    scheme_value += addition[i]
                    break
                else:
                    continue
        return scheme_value

    def union_born(self, agent):
        """
            联盟初始分配函数
            一个算子为一个联盟
            return： 联盟分配后的结果
        """
        id_list = []
        union_list = []
        union_result = {}
        for operator in self.operators:
            obj_id = operator['obj_id']
            id_list.append(obj_id)  # 提取出所有的算子id
        # for i in range(0, len(id_list), 2):  # 两个算子一组
        #     b = id_list[i:i + 2]
        #     union_list.append(b)
            union_list.append([obj_id])
        for i in range(len(union_list)):
            # if len(union_list[i]) == 1:
                # union = {0: {16: 2, 17: 1}, 1: {18: 2, 19: 1}, 2: {20: 2, 21: 1}, 3: {22: 2, 23: 1}}
                # union_result.update({i: {union_list[i][0]: random.choice(self.task)}})  # 为联盟中的每个算子分配行为树
                # union1 = {0: [(16, 2), (17, 1)], 1: [(18, 2), (19, 1)], 2: [(20, 2), (21, 1)], 3: [(22, 2), (23, 1)]}
            union_result.update({i: [(union_list[i][0], random.choice(self.task))]})  # 为联盟中的每个算子分配行为树
            # else:
            #     # union_result.update({i: {union_list[i][0]: random.choice(self.task), union_list[i][1]: random.choice(self.task)}})
            #     union_result.update({i: [(union_list[i][0], random.choice(self.task)), (union_list[i][1], random.choice(self.task))]})  # 为联盟中的每个算子分配行为树
        return union_result  # [[1,2],[3,4]]

    def change_union(self, union1, max_member):  # 转移联盟函数
        """
        判断算子是否需要转移联盟
        param： union 一种联盟分配的情况
        return： 转移联盟后的结果
        """

        union2 = []
        trash = {}
        # max_member = 3
        for j in range(len(union1)):  # 遍历每一个联盟
            for k in range(len(union1[j])):  # 遍历每一个联盟中的每一个算子
                a = union1[j][k]

                for i in union1:  # 遍历联盟中每一个key
                    union3 = copy.deepcopy(union1)  # 深拷贝 供下面删除用
                    union4 = copy.deepcopy(union1)
                    if len(union3[i]) < max_member + 1:  # 如果每一个联盟中成员个数小于最大成员数
                        union3[i].append(union1[j][k])  # 才会将算子添加到新的联盟中
                        union3[j].remove(a)  # 把算子从原来的联盟中删除
                        union2.append(union3)  # 结果 列表套字典
                        trash.update({i: [a]})
                    else:
                        for number, item in trash.items():
                            union4.pop(number)  # 删除已经转移过算子的联盟
                        for num, item in union4.items():  # 遍历剩下的（没有转移算子的）联盟
                            if len(item) < max_member + 1:  # 如果每一个联盟中成员个数小于最大成员数
                                union3[num].append(union1[j][k])  # 将算子添加到新的联盟中
                                union3[j].remove(a)
                                union2.append(union3)
        return union2

    def group_three_cal(self, list_f):  # 三个算子一组的效能计算
        cal_list = []
        count_result = 0

        if self.mission in self.efficiency and self.mission in self.addition:  # 存储当前mission对应下的效能值和加成值
            efficiency = self.efficiency[self.mission]
            addition = self.addition[self.mission]
        else:
            return 0

        group = list(itertools.combinations(list_f, 2))  # 两个算子一组
        for i in group:
            lst = copy.deepcopy(list(list_f))
            for j in lst:
                if j in lst:
                    lst.remove(j)
            single = lst[0]  # 提取单个的元素
            cal_single = efficiency.get(single)
            if cal_single:
                count_result += cal_single
            cal_group = addition.get(i)
            if cal_group:
                cal_increment = 2 * cal_group  # 协同增量 = 0.25*
                count_result += cal_increment
                count_result += cal_group
            else:
                new_group = list(i)  # 反转组合 找
                new_group.reverse()
                new = tuple(new_group)
                cal_group_new = addition.get(new)
                if cal_group_new:
                    cal_increment = 2 * cal_group_new  # 协同增量 = 0.25*
                    count_result += cal_increment
                    count_result += cal_group_new

            cal_list.append(count_result)
        calculation = max(cal_list)
        return calculation

    def add_calculate(self, agent, union):  # union改一下
        """
        计算关联指标的函数
        param： union 一种联盟分配的情况
        return： int 此种分配下的回报值
        """
        lst = []
        count_result = 0
        task = {}
        tuplee_list = []
        three_list = [] # 存放联盟成员为三个的算子
        # 先计算当前联盟下的效能值
        if self.mission in self.efficiency and self.mission in self.addition:  # 存储当前mission对应下的效能值和加成值
            efficiency = self.efficiency[self.mission]
            addition = self.addition[self.mission]
        else:
            return 0
        for num, item in union.items():
            if item:
                lst.clear()
                for i in range(len(item)):
                    obj_id = item[i][0]
                    betree = item[i][1]
                    bop = agent.get_bop(obj_id)
                    if bop:
                        subtype = bop['sub_type']
                        lst.append({obj_id: tuple([subtype, betree])})
                        # lst.append(tuple([subtype, betree]))
                list_f = tuple(lst)
                print(list_f)
                if len(list_f) == 1:  # 联盟中算子数量低于3时 关联指标直接查表
                    for i in range(len(list_f)):
                        for obj_id, tuplee in list_f[i].items():
                            calculation = efficiency.get(tuplee)
                            if calculation:
                                count_result += calculation

                elif len(list_f) == 2:
                    # calculation = addition.get((list_f))
                    # if calculation:
                    #     count_result += calculation
                    # lst.clear()
                    for i in range(len(list_f)):
                        for obj_id, tuplee in list_f[i].items():
                            task.update({obj_id: tuplee[1]})
                    count_result += self.calculate_return(agent, task)

                    # print(count_result)
                else:  # 联盟中算子数量大于2时 分两种情况 1.三个一组 2.两个一组
                    if len(list_f) == 3:
                        for i in range(len(list_f)):
                            for obj_id, tuplee in list_f[i].items():
                                three_list.append(tuplee)
                        count_result += self.group_three_cal(three_list)
                    else:  # 三个以上的情况 1.2个一组
                        for i in range(len(list_f)):
                            for obj_id, tuplee in list_f[i].items():
                                task.update({obj_id: tuplee[1]})  # 先变成task的形式放在两个一组函数中
                                tuplee_list.append(tuplee)  # 为了放在三个一组函数里面用
                        count_result_2 = self.calculate_return(agent, task)
                        count_result_3 = self.three_calculate_return(agent, task)  # 三个一组
                        if count_result_3 > count_result_2:
                            count_result += count_result_3
                        else:
                            count_result += count_result_2
        return count_result



    def change_betree(self,union):
        """
        改变算子的行为树
        param： union 一种联盟分配的情况
        return：union 改变行为树后的联盟
        """
        # union1 = {0: [(17, 1)], 1: [(16, 2), (18, 2), (19, 1)], 2: [(20, 2), (21, 1), (22, 2)], 3: [(23, 1)]}
        union2 = []
        task_gather_1 = [0, 1, 2]
        new_task = []
        for j in range(len(union)):
            for k in range(len(union[j])):
                a = union[j][k]
                task = union[j][k][1]
                task_gather = copy.deepcopy(task_gather_1)
                task_gather.remove(task)
                for new in task_gather:
                    single_list = list(union[j][k])  # 把每一个元组变成列表的形式 便于添加元素
                    single_list[1] = new
                    single_tuple = tuple(single_list)
                    union3 = copy.deepcopy(union)
                    union3[j].append(single_tuple)
                    union3[j].remove(a)
                    union2.append(union3)  # 结果 列表套字典
                # union2.remove(union2[k])
        return union2


    def three_calculate_return(self, agent, task):
        """
        计算期望回报函数（三个一组）
        param： task 一种任务分配的情况
        return： int 此种分配下的回报值
        """

        group_standby = []
        alliance = []
        alliance_value = {}
        alliance_result = {}
        scheme_value = 0
        value_dict = {}
        if self.mission in self.efficiency and self.mission in self.addition:  # 存储当前mission对应下的效能值和加成值
            efficiency = self.efficiency[self.mission]
            addition = self.addition[self.mission]
        else:
            return 0

        def set_rank(a_dict):
            a_sort_list = sorted(a_dict.items(), key=lambda x: x[1], reverse=True)
            a_sort_dict = {}
            for n, s in a_sort_list:
                a_sort_dict[n] = s
            return a_sort_dict


        for obj_id, obj_task in task.items():
            bop = agent.get_bop(obj_id)
            if bop:
                group_standby.append((bop['sub_type'], obj_task))
            else:
                return 0

        group = list(itertools.combinations(group_standby, 3))
        for group_single in group:
            value = self.group_three_cal(group_single)
            if value:
                value_dict.update({group_single: value})
        if value_dict:
            value_sort = set_rank(value_dict)
        standby = copy.deepcopy(group_standby)
        for value_single,value in value_sort.items():
            alliance_0 = value_single[0]
            alliance_1 = value_single[1]
            alliance_2 = value_single[2]
            if alliance_0 in standby:
                standby.remove(alliance_0)
                if alliance_1 in standby:
                    standby.remove(alliance_1)
                    if alliance_2 in standby:
                        alliance_result.update({value_single: value})
                        standby.remove(alliance_2)
                    else:
                        standby.append(alliance_1)
                        standby.append(alliance_0)
                else:
                    standby.append(alliance_0)
            else:
                break
        for efficiency_single in standby:
            if efficiency_single in efficiency.keys():
                scheme_value += efficiency[efficiency_single]
        for alliance_single, value in alliance_result.items():
              scheme_value += value
        return scheme_value